package com.swdegao.iot.netty.server.guoxinhandler;

import com.alibaba.fastjson.JSON;
import com.swdegao.iot.SwdegaoIotMgtServerApplication;
import com.swdegao.iot.netty.entity.*;
import com.swdegao.iot.netty.service.impl.TerminalsServiceImpl;
import com.swdegao.iot.netty.utils.ConvertUtils;
import com.swdegao.iot.netty.utils.DataResction;
import com.swdegao.iot.netty.utils.ExceptionUitls;
import com.swdegao.iot.netty.utils.RedisUtils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.net.InetSocketAddress;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class GuoXinParseMessgaeHandler extends SimpleChannelInboundHandler<Object>{

	// 定义一个全局的记录器，通过LoggerFactory获取
	private final static Logger logger = LoggerFactory.getLogger(GuoXinParseMessgaeHandler.class);

	@Autowired
	private RedisUtils redisUtils = SwdegaoIotMgtServerApplication.getBean(RedisUtils.class);
	static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

	private HandlerMessage hm = new HandlerMessage();


	@SuppressWarnings("unused")
	private String tempTime = null;//用于比较心跳是否超时
	private Boolean flag = true;
	@Override
	protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { // (4)
		System.out.println("进入端口 8211  -------国信类");
		InetSocketAddress clientAddr = (InetSocketAddress)ctx.channel().remoteAddress();
		String clientIp = clientAddr.getHostName();
		ByteBuf in = (ByteBuf)msg;
		byte[] barray = new byte[in.readableBytes()];
		in.getBytes(0,barray);
		logger.info("获取到数据："+new String(barray));
		String ChannelID = null;
		try{
			if(!ConstGuoXin.HEAD.equals(in.getByte(0))){
				//发送注册包、心跳包，验证通道
				ChannelID = new String(barray);
				ChannelID = ChannelID.substring(0,10);
				// 更换连接ID
				if (!ConstGuoXin.hasChannelID(ChannelID)) {
					String realChannelID = ConstGuoXin.isChannel(ctx.channel());
					//logger.info("!ConstGuoXin.hasChannelID,realChannelID " +realChannelID);
					ConstGuoXin.ChangeClientId(realChannelID, ChannelID);
					// 记录上线记录
					onoffLineAction(ChannelID, Parameter.online_des,1);// 记录上线
					onoffLineForCenter(ChannelID,1);
					logger.info("--------------ip初创连接:"+clientIp+","+ChannelID);
				}
				// 检查重复链接ID 不同实例 切换实例
				if (ConstGuoXin.ischangeChannelID(ChannelID, ctx.channel())) {
					//logger.info("ConstGuoXin.ischangeChannelID,ChannelID " +ChannelID);
					ConstGuoXin.changeChannel(ChannelID, ctx.channel());
					// 记录重复上线记录
					onoffLineAction(ChannelID, Parameter.reonline_des,0);// 记录下线
					onoffLineForCenter(ChannelID,0);
					logger.info("--------------ip更新连接:"+clientIp+","+ChannelID);
				}
				hm.setImei(ChannelID);
				hm.setActionTpye((byte)0x00);
				hm.setSendMsg(ToDeviceClockMsg());
				hm.setRecevieMsg(in);
				ctx.writeAndFlush(hm.getSendMsg());
			}else{

				// 数据类型:0x81,0x82,0x83,0x84
				Byte type = DataResction.ResctionDataType(in.getByte(4));
				hm.setActionTpye(type);
				//hm.setImei(ChannelID);
				hm.setRecevieMsg(in);

			}

			ctx.fireChannelRead(hm);
		}
		catch(Exception e){
			logger.error(ChannelID+e.getMessage());
		} finally {
			//ReferenceCountUtil.release(in);
			//logger.error(ChannelID+"ParseMessgaeHandlerfinally");
		}
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
		//logger.info("TCP通道已经连接");
		Channel incoming = ctx.channel();
		ConstGuoXin.add(String.valueOf(UUID.randomUUID()), ctx.channel());
		channels.add(ctx.channel());
		//logger.info("client " + incoming.remoteAddress() + "上线");
	}

	@Override
	public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
		inactiveAction(ctx);
		// 记录下线
		//logger.info("Disconnected client " + ctx.channel().remoteAddress() + "掉线" + channelId);
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
		Channel incoming = ctx.channel();
		//logger.info("client " + incoming.remoteAddress() + "异常" + cause.getMessage());
		// 当出现异常就关闭连接
		cause.printStackTrace();
		// ctx.close();
	}

	/**
	 * 上线操作
	 *
	 * @param imei
	 * @param
	 */
	private void onoffLineAction(String imei, String type,int status) {
		OnOffData onOff = new OnOffData();
		onOff.setImei(imei);
		onOff.setCreatetime(System.currentTimeMillis());
		onOff.setAction(type);
		redisUtils.lPush(imei + Parameter.on_off_info, JSON.toJSONString(onOff));// 存储所有updata数据
	}
	/**
	 * 上线下线操作
	 *
	 * @param imei
	 * @param
	 */
	@SuppressWarnings("unused")
	private void onoffLineForCenter(String imei, int status) {
		Terminals terminal = new Terminals();
		terminal.setImei(imei);
		terminal.setOnlinestatus(status);
		//ts.updateTerminalOnlineStatus(terminal);
	}
	/**
	 * 下线完整操作
	 */
	private void inactiveAction(ChannelHandlerContext ctx){
		String channelId = ConstGuoXin.getChannelIds(ctx.channel());
		try{
			if(!"".equals(channelId) && !channelId.contains("_")){
				onoffLineAction(channelId, Parameter.offline_des,0);// 记录下线
				onoffLineForCenter(channelId,0);
				//清掉redis中关于心跳记录
				ImeiInfo imeiInfo = JSON.parseObject(redisUtils.hmGet(Parameter.imei_info,channelId).toString(), ImeiInfo.class);
				imeiInfo.setHeartbeat_delay_num(0);
				imeiInfo.setHeartbeat_registered_num(0);
				redisUtils.hmSet(Parameter.imei_info, channelId, JSON.toJSONString(imeiInfo));
			}
		}catch (Exception e){
			logger.debug(ExceptionUitls.getExceptionInfo(e));
		}finally {
			ConstGuoXin.remove(ctx.channel());
			channels.remove(ctx.channel());
		}

	}

	public String getTimeNow() {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return df.format(new Date());
	}

	/**
	 * 获取超时时间
	 * @param timeNow
	 */
	public String getTimeOut(String timeNow) {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Calendar cal = new GregorianCalendar();

		try {
			cal.setTime(df.parse(timeNow));
			cal.add(Calendar.SECOND, Parameter.outtime_hear);

		} catch (ParseException e) {
			e.printStackTrace();
		}
		return df.format(cal.getTime());
	}

	/**
	 * 比较超时时间，是否超时
	 */
	public int CompareOutTime(String timeNow,String timeAfter, SimpleDateFormat timestampFormat)
	{
        if(timeNow.equals(timeAfter)) // same
            return 1;
        try {
            Date timesN = timestampFormat.parse(timeNow);
            Date timesA = timestampFormat.parse(timeAfter);
            if(timesA.after(timesN)) // time 1 is newer
                return 1;
            else return -1;
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 1;
	}

	/**
	 *
	 * @param
	 * @param
	 * @return
	 */
	public ByteBuf ToDeviceClockMsg()
     {
		 SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
		 String date = df.format(new Date());
		 byte[] temp2_ = ConvertUtils.getDateFromStrDX(date, 7);
         byte[] msg = new byte[8 + temp2_.length];
         msg[0] = (byte) 0xaa;
         msg[1] = 0x55;
         msg[2] = 0x07;
		 msg[3] = 0x00;
         msg[4] = 0x16;
		 msg[5] = 0x00;
		 msg[6] = 0x00;

         System.arraycopy(temp2_, 0, msg, 7, 7);
         msg[msg.length - 1] = ConvertUtils.getTotalForByte(msg);

         return Unpooled.wrappedBuffer(msg);
     }


	public ByteBuf GetSuccessSignal(String imei,byte type,boolean suc) {
		byte[] msg = new byte[23];
        msg[0] = (byte) 0x80;
        msg[1] = 0x23;
        msg[2] = 0;
        msg[3] = type;
        byte[] temp = imei.getBytes();
        System.arraycopy(temp, 0, msg, 4, 15);//类型、imei
        msg[19] = (byte)(suc ? 0x73 : 0x74);//应答状态
        msg[20] = ConvertUtils.getTotalForByte(msg);//校验和
        msg[21] = 0x0d;
        msg[22] = 0x0a;
		return  Unpooled.wrappedBuffer(msg);
	}
	/**
	 * 预置命令
	 * @param imei
	 * @param presetCommand
	 * @return
	 * @throws DecoderException
	 */
	public ByteBuf GetPresetCommand(String imei,PresetCommand presetCommand) throws DecoderException {
		byte[]  downData = Hex.decodeHex(presetCommand.getDownData());
		int msg_length = 22 + downData.length;
		int msg_length_h = msg_length/100;
		int msg_length_l = msg_length -(msg_length/100)*msg_length_h;
		byte[] msg = new byte[msg_length];
        msg[0] = (byte) 0x80;
        msg[1] = (byte)Integer.parseInt(msg_length_l+"", 16);
        msg[2] = (byte)Integer.parseInt(msg_length_h+"", 16);
        msg[3] = (byte) 0x86;
        byte[] temp = imei.getBytes();
        System.arraycopy(temp, 0, msg, 4, 15);//类型、imei
        System.arraycopy(downData, 0, msg, 19, downData.length);//类型、imei
        msg[msg_length-3] = ConvertUtils.getTotalForByte(msg);//校验和
        msg[msg_length-2] = 0x0d;
        msg[msg_length-1] = 0x0a;
		return  Unpooled.wrappedBuffer(msg);
	}


}
